﻿using gt.rediscache.core.Entry;
using System;
using System.Collections.Generic;
using System.Linq;

namespace gt.rediscache.core.Connections.Route
{
    internal class MultipleNodeRouter : IRedisNodeRouter
    {
        private const int m_slotCount = 16384;
        private Dictionary<int, string> m_slotContainer = null;

        public MultipleNodeRouter(List<RouteData> routes)
        {
            if (routes == null || routes.Count == 0) throw new ArgumentNullException("routes");
            if (routes.Any(x => string.IsNullOrEmpty(x.NodeName)
                                 || x.SlotFrom > x.SlotTo
                                 || x.SlotTo >= m_slotCount
                                 || x.SlotFrom < 0)) throw new InvalidOperationException("error routedata.");
            if (routes.Select(x => x.NodeName).Distinct().Count() != routes.Count) throw new InvalidOperationException("route name can not be duplicate.");

            m_slotContainer = new Dictionary<int, string>();
            foreach (var r in routes)
            {
                for (int i = r.SlotFrom; i <= r.SlotTo; i++)
                {
                    m_slotContainer.Add(i, r.NodeName);
                }
            }
        }

        private int GetSlotByKey(string key)
        {
            int h = 0;
            for (int i = 0; i < key.Length; i++)
            {
                h = 33 * h + (int)key[i];
            }
            return Math.Abs(h) % m_slotCount;
        }

        public string GetClientServerName(string key)
        {
            var slot = GetSlotByKey(key);
            return m_slotContainer[slot];
        }
    }
}
